#include <stdio.h>
#include <stdlib.h>
#include "pila.h"

#define TAM_AGRANDAR 2
#define TAM_ACHICAR 0.5
#define TAM_INICIAL 32
#define RELACION_LIMITE 0.25

struct _pila {
    void** datos;
    size_t tamanio;
    size_t cantidad;
};

pila_t* pila_crear()
{
	pila_t* pila = malloc(sizeof(pila_t));
	if (pila == NULL) return NULL;
	
	pila->tamanio = TAM_INICIAL;	//Tamaño inicial por defecto
	pila->cantidad = 0;
	
	pila->datos = (void**) malloc(pila->tamanio*sizeof(void*));
	if (pila->datos == NULL) 
	{
		free(pila);
		return NULL;
	}

	return pila;
}

void pila_destruir(pila_t *pila)
{
	free(pila->datos);
	free(pila);
}

bool pila_esta_vacia(const pila_t *pila)
{
	if (pila->cantidad == 0)
	{
		return true;
	} else {
		return false;
	}
}

bool pila_redimensionar(pila_t *pila, float nueva_dimension)
{
		pila->tamanio = pila->tamanio*nueva_dimension;	
		void** datos_nuevos = realloc(pila->datos, pila->tamanio*sizeof(void*));
		if (datos_nuevos == NULL) return false;
		pila->datos = datos_nuevos;

		return true;
}

bool pila_apilar(pila_t *pila, void* valor)
{
	
	if (pila->cantidad == pila->tamanio) // Si llegue al tope del espacio de memoria
	{
		//La pila se agranda al doble de su tamanio inicial
		if (!pila_redimensionar(pila, TAM_AGRANDAR))
			return false;				//Se devuelve false si la reserva de memoria falla
	}

	pila->datos[pila->cantidad] = valor;
	pila->cantidad++;
	
	return true;
}

void* pila_ver_tope(const pila_t *pila)
{
	if (pila_esta_vacia(pila)) 
	{
		return NULL;
	} else {
		return pila->datos[pila->cantidad-1];	
	}
}

void* pila_desapilar(pila_t *pila)
{
	if (pila_esta_vacia(pila)) return NULL;
	
	void* elemento = pila_ver_tope(pila);
	pila->cantidad--;
	
	// Si la cantidad de datos es un cuarto del tamanio de la pila, se achica a la mitad
	// Este '1/4' se usa para evitar redimensionar la pila constantemente, que valores
        // como 1/2 ocasionarian

	if ((pila->cantidad) <= (pila->tamanio)*RELACION_LIMITE && pila->tamanio > TAM_INICIAL)
	{
		pila_redimensionar(pila, TAM_ACHICAR);
	}

	return elemento;
}

